﻿using Elasticsearch.Net;
using Nest;
using NHibernate.Cfg;
using NHibernate.Search.ElasticSearch.Attributes;
using NHibernate.Search.ElasticSearch.Mapping;
using NHibernate.Type;
using System;
using System.Collections.Generic;

namespace NHibernate.Search.ElasticSearch.Cfg
{
    public class NHibernateSearchConfiguration
    {
        private Configuration cfg;
        private NHibernateSearchConfiguration(Configuration cfg)
        {
            this.cfg = cfg;
            this.classes = new Dictionary<string, IndexedClass>();
        }
        private static NHibernateSearchConfiguration nHibernateSearchConfiguration;
        public static NHibernateSearchConfiguration Initialize(Configuration cfg)
        {
            if (nHibernateSearchConfiguration == null)
            {
                nHibernateSearchConfiguration = new NHibernateSearchConfiguration(cfg);
                nHibernateSearchConfiguration.InitializeElasticClient();
                nHibernateSearchConfiguration.InitializeIndexClasses();

                ConfigurationExtensions.AddNHibernateSearchConfiguration(nHibernateSearchConfiguration);
            }
            return nHibernateSearchConfiguration;
        }
        internal static readonly string ElasticUriKey = "elasticsearch.uri";
        private const string IndexNameKey = "elasticsearch.index";
        private ElasticClient elasticClient;
        private string index;
        public string Index
        {
            get { return this.index; }
        }
        private void InitializeElasticClient()
        {
            var node = new Uri(cfg.Properties[ElasticUriKey]);
            var settings = new ConnectionSettings(node);

            elasticClient = new ElasticClient(settings);
            this.index = GetSessionFactoryName();

            //TODO 检查索引是否存在，如果不存在创建
            IndexExistsRequest indexExistsRequest = new IndexExistsRequest(index);
            bool exist = elasticClient.IndexExists(indexExistsRequest).Exists;
            if (!exist)
            {
                CreateIndexRequest createIndexRequest = new CreateIndexRequest(index);
                IndexSettings indexSettings = new IndexSettings();
                createIndexRequest.Settings = indexSettings;
                elasticClient.CreateIndex(createIndexRequest); 
            }

        }
        internal string GetSessionFactoryName()
        {
            return cfg.GetProperty(IndexNameKey) ?? cfg.GetProperty(NHibernate.Cfg.Environment.SessionFactoryName) ?? "inovout";
        }
        public ElasticClient GetElasticClient()
        {
            return this.elasticClient;
        }
        private IDictionary<string, IndexedClass> classes;
        public bool IndexClassExists(string entityName)
        {
            return classes.Keys.Contains(entityName);
        }
        public IndexedClass GetIndexClass(System.Type entityType)
        {
            return GetIndexClass(entityType.FullName);
        }
        public IndexedClass GetIndexClass(string entityName)
        {
            return classes[entityName];
        }
        private void InitializeIndexClasses()
        {
            foreach (var mapping in cfg.ClassMappings)
            {
                if (!this.IsIndexed(mapping.MappedClass))
                    continue;

                classes.Add(mapping.EntityName, BuildIndexClass(mapping.MappedClass));
            }
        }
        private IndexedClass BuildIndexClass(System.Type indexedType)
        {
            return new IndexedClass(this, indexedType);
        }
        private bool IsIndexed(System.Type type)
        {
            return type.IsDefined(typeof(IndexedAttribute), true);
        }


    }
}
